#pragma warning (disable: 4290) //Current visual studio does not support throw declaration
#include "SubtitleHandler.h"
#include <vector>
#include <map>
#include <sstream>
#include "FileOpener.h"
#include "Exceptions.h"
#include <boost/algorithm/string.hpp>
using std::vector;
using std::map;

namespace SubPlayer
{
    void * SubtitleHandler::pObject;

    SubtitleHandler::SubtitleHandler(const wstring& dllPath, const wstring& encoding, HWND hWnd) throw (Exceptions::SubtitleLoadException) :
        plugin(dllPath),
        usedEncoding(encoding),
        lastError(L""),
        hWnd(hWnd)
    {
        if (LoadSubtitles() != 0) {
            throw Exceptions::SubtitleLoadException(lastError);
        }
    }

    SubtitleHandler::~SubtitleHandler()
    {
    }

    int SubtitleHandler::LoadSubtitles()
    {
        lastError = L"";
        wstring openedFile;
        int openState = OpenSubFile(openedFile);
        switch (openState) {
        case 1:
            lastError = L"No suitable subtitle module found. Please install some subtitle module, or change path to your modules in settings.";
            return 4;
            break;
        case 2:
            lastError = L"You have not selected any subtitle file. You can open supported selected file throu menu.";
            return 5;
            break;
        case 3:
            lastError = L"Selected subtitle file cannot be opened. It is probably corrupted. Please choose another file.";
            return 3;
            break;
        }
        
        if (plugin.LoadPlugin(GetExtension(openedFile)) != 0) {
            lastError = L"Used plugin does not support all required operations. It is probably unfinished and cannot be used\n"
                        L"You can either load another plugin for selected type of subtitles, or use another type of subtitles";
            return 1;
        }

        if (plugin.Initialize(openedFile.c_str(), usedEncoding.c_str()) != 0) {
            lastError = plugin.GetError();
            return 2;
        }
        return 0;
    }

    int SubtitleHandler::OpenSubFile(wstring& subtitlePath)
    {
        vector<wstring> supportedTypes = plugin.GetSupportedTypesList();
        if (supportedTypes.size() == 0) {
            return 1;
        }
        map<wstring, wstring> supportedTypeFilters;
        for (vector<wstring>::iterator it = supportedTypes.begin(); it != supportedTypes.end(); it++) {
           supportedTypeFilters.insert(std::make_pair(boost::to_upper_copy(*it) + L" subtitle file", returnPattern(*it)));
        }

        if (supportedTypeFilters.size() > 1) {
            std::wstringstream list;
            CreatePattern(supportedTypes);
            std::copy(supportedTypes.begin(), supportedTypes.end(), std::ostream_iterator<wstring, wchar_t, std::char_traits<wchar_t>>(list, L","));
            //supportedTypeFilters.insert(std::make_pair(L"All supported subtitles types", list.str));
            // TODO: opravit tak aby vlozilo zoznam vsetkych podporovanych formatov
        }

        FileOpener fileOpener(supportedTypeFilters);
        HRESULT hr = fileOpener.ShowDialog(subtitlePath);
        if (hr == S_OK) {
            subtitlePath.shrink_to_fit();
            return 0;
        }
        else if (hr == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
            return 2;
        }
        return 3; //error occured
    }

    void SubtitleHandler::StartPlaying()
    {
        long endTime;
        if (plugin.GetFirstSub(currentSub, endTime) != 0) {
            currentSub = L"Error";
        }
        else {
            InvalidateRect(hWnd, NULL, TRUE);
            UpdateWindow(hWnd);
            timer.Reset();
            timer.AddTimer(endTime, TimerProc_Wrapper);
        }
    }

    wstring SubtitleHandler::test()
    {
        long endTime;
        wstring sub;
        if (plugin.GetFirstSub(sub, endTime) != 0) {
            return L"Cannot get sub";
        }
        else {
            #ifdef _DEBUG
            wcout<<endTime<<endl;
            #endif
            return sub;
        }
    }

    VOID CALLBACK SubtitleHandler::TimerProc_Wrapper(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)
    {
        SubtitleHandler *pSomeClass = (SubtitleHandler*)pObject; // cast the void pointer
        pSomeClass->TimerEvent(hwnd, uMsg, idEvent, dwTime); // call non-static function
    }

    VOID CALLBACK SubtitleHandler::TimerEvent(_In_ HWND hwnd, _In_ UINT, _In_ UINT_PTR idEvent, _In_ DWORD dwTime)
    {
        #ifdef _DEBUG
        wcout<<L"Timer - "<<dwTime<<endl;
        #endif
        timer.RemoveTimer(hwnd, idEvent);
    }

}